﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Input;

namespace Pavilion.DesignerTool.ViewTools
{
    public static class ConnectionManager
    {
        #region ConnectionPendingEvent

        public static readonly RoutedEvent ConnectionPendingEvent = EventManager.RegisterRoutedEvent("ConnectionPending", RoutingStrategy.Bubble,
            typeof(RoutedEventHandler), typeof(ConnectionManager));

        public static void AddConnectionPendingHandler(DependencyObject d, RoutedEventHandler handler)
        {
            UIElement uie = d as UIElement;
            if (uie != null)
            {
                uie.AddHandler(ConnectionManager.ConnectionPendingEvent, handler);
            }
        }

        public static void RemoveConnectionPendingEventHandler(DependencyObject d, RoutedEventHandler handler)
        {
            UIElement uie = d as UIElement;
            if (uie != null)
            {
                uie.RemoveHandler(ConnectionManager.ConnectionPendingEvent, handler);
            }
        }

        #endregion

        #region IsConnectableProperty

        public static readonly DependencyProperty IsConnectableProperty = DependencyProperty.RegisterAttached("IsConnectable", typeof(Boolean), typeof(ConnectionManager),
            new FrameworkPropertyMetadata());

        public static void SetIsConnectable(DependencyObject element, bool value)
        {
            element.SetValue(IsConnectableProperty, value);
        }

        public static Boolean GetIsConnectable(DependencyObject element)
        {
            return (bool)element.GetValue(IsConnectableProperty);
        }
                
        #endregion

        #region AnchorGridStyleProperty

        public static readonly DependencyProperty AnchorGridStyleProperty = DependencyProperty.RegisterAttached("AnchorGridStyle", typeof(Style),
            typeof(ConnectionManager), new PropertyMetadata(null));

        public static void SetAnchorGridStyleProperty(DependencyObject element, Style value)
        {
            element.SetValue(AnchorGridStyleProperty, value);
        }

        public static Style GetAnchorGridStyleProperty(DependencyObject element)
        {
            return (Style)element.GetValue(AnchorGridStyleProperty);
        }
        
        #endregion

        #region MenuItemInvokerProperty

        public static readonly DependencyProperty MenuItemInvokerProperty = DependencyProperty.RegisterAttached("MenuItemInvoker", typeof(MenuItem), typeof(ConnectionManager),
             new FrameworkPropertyMetadata(MenuItemInvoker_PropertyChanged));

        public static void SetMenuItemInvoker(DependencyObject element, MenuItem value)
        {
            element.SetValue(MenuItemInvokerProperty, value);
        }

        public static MenuItem GetMenuItemInvoker(DependencyObject element)
        {
            return (MenuItem)element.GetValue(MenuItemInvokerProperty);
        }
        
        #endregion

        private static ListBoxItem StartingListBox { get; set; }

        public static void MenuItemInvoker_PropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {           
            (args.NewValue as MenuItem).Click += (sender, e) => MenuItemInvoker_Click(obj as FrameworkElement);
        }

        private static void MenuItemInvoker_Click(FrameworkElement invokerElement)
        {
            var itemsPanel = PavilionVisualTreeHelper.GetAncestor(invokerElement, typeof(Canvas)) as Canvas;
            StartingListBox = PavilionVisualTreeHelper.GetAncestor(invokerElement, typeof(ListBoxItem)) as ListBoxItem;

            Point lineAdornerStart = Connection.GetPointOnCenter(invokerElement);
            LineAdorner lineAdorner = new LineAdorner(itemsPanel, lineAdornerStart);
            AdornerLayer.GetAdornerLayer(itemsPanel).Add(lineAdorner);

            lineAdorner.MouseLeftButtonDown += new MouseButtonEventHandler(LineAdorner_MouseLeftButtonDown);
        }

        private static void LineAdorner_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var lineAdorner = sender as LineAdorner;
            ListBoxItem hitItem = GetHitListBoxItem(lineAdorner, e);

            if (hitItem != null)
            {
               hitItem.RaiseEvent(new ConnectionPendingRoutedEventArgs(StartingListBox, hitItem, ConnectionPendingEvent));
            }

            FreeLineAdorner(lineAdorner);
        }

        private static void FreeLineAdorner(LineAdorner lineAdorner)
        {
            lineAdorner.ReleaseMouseCapture();
            lineAdorner.MouseLeftButtonDown -= new MouseButtonEventHandler(LineAdorner_MouseLeftButtonDown);
            AdornerLayer.GetAdornerLayer(lineAdorner.AdornedElement).Remove(lineAdorner);
        }
        
        private static ListBoxItem GetHitListBoxItem(LineAdorner lineAdorner, MouseButtonEventArgs e)
        {
            ListBoxItem hitItem = null;

            VisualTreeHelper.HitTest(lineAdorner.AdornedElement, null,
                hitTestParameters: new PointHitTestParameters(e.GetPosition(lineAdorner.AdornedElement)),
                resultCallback: (HitTestResult result) =>
                {
                    hitItem = PavilionVisualTreeHelper.GetAncestor(result.VisualHit, typeof(ListBoxItem)) as ListBoxItem;
                    return HitTestResultBehavior.Stop;
                });

            return hitItem;
        }
    }

    public class ConnectionPendingRoutedEventArgs : RoutedEventArgs
    {
        public ListBoxItem Start { get; set; }
        public ListBoxItem End { get; set; }

        public ConnectionPendingRoutedEventArgs(ListBoxItem start, ListBoxItem end, RoutedEvent routedEvent) : base(routedEvent)
        {
            this.Start = start;
            this.End = end;
        }
    }
}
